// uvm_tb/tb_top.sv
`include "uvm_macros.svh"
import uvm_pkg::*;

module tb_top;

    // ========================================================================
    // Clock and Reset
    // ========================================================================
    logic clk;
    logic rst_n;

    // Clock generation
    initial begin
        clk = 0;
        forever #5 clk = ~clk;  // 10ns period -> 100MHz
    end

    // Reset generation
    initial begin
        rst_n = 0;
        #20;
        rst_n = 1;
    end

    // ========================================================================
    // Interface and DUT Instantiation
    // ========================================================================

    // Instantiate the UVM testbench interface (for driver/monitor)
    binary_alu_if vif (
        clk,
        rst_n
    );

    // Instantiate DUT-specific interfaces
    // These will be connected to the DUT and driven/monitored via vif
    aru_mul_cfg_if cfg_if (
        clk,
        rst_n
    );
    aru_payload_if top_if (
        clk,
        rst_n
    );
    aru_payload_if left_if (
        clk,
        rst_n
    );
    aru_payload_if bottom_if (
        clk,
        rst_n
    );
    aru_payload_if right_if (
        clk,
        rst_n
    );

    // Connect UVM interface to DUT interfaces
    // Config channel
    assign cfg_if.vld     = vif.cfg_vld;
    assign vif.cfg_rdy    = cfg_if.rdy;
    assign cfg_if.mode    = vif.cfg_mode;
    assign cfg_if.scalar  = vif.cfg_scalar;

    // Top input channel
    assign top_if.vld     = vif.top_vld;
    assign vif.top_rdy    = top_if.rdy;
    assign top_if.dat     = vif.top_dat;
    assign top_if.sdb     = vif.top_sdb;

    // Left input channel
    assign left_if.vld    = vif.left_vld;
    assign vif.left_rdy   = left_if.rdy;
    assign left_if.dat    = vif.left_dat;
    assign left_if.sdb    = vif.left_sdb;

    // Bottom input channel
    assign bottom_if.vld  = vif.bottom_vld;
    assign vif.bottom_rdy = bottom_if.rdy;
    assign bottom_if.dat  = vif.bottom_dat;
    assign bottom_if.sdb  = vif.bottom_sdb;

    // Right output channel
    assign vif.right_vld  = right_if.vld;
    assign right_if.rdy   = vif.right_rdy;
    assign vif.right_dat  = right_if.dat;
    assign vif.right_sdb  = right_if.sdb;

    // Instantiate the DUT
    aru_binary_mul dut (
        .clk                (clk),
        .rst_n              (rst_n),
        .u_aru_cfg_if       (cfg_if.in),
        .u_aru_pld_top_if   (top_if.in),
        .u_aru_pld_left_if  (left_if.in),
        .u_aru_pld_bottom_if(bottom_if.in),
        .u_aru_pld_right_if (right_if.out)
    );

    // ========================================================================
    // UVM Test Execution
    // ========================================================================
    initial begin
        // Place the interface into the UVM configuration database
        uvm_config_db#(virtual binary_alu_if)::set(null, "uvm_test_top", "vif", vif);

        // Run the test. The test name is specified on the command line
        // with +UVM_TESTNAME=test_name
        run_test();
    end

    // ========================================================================
    // Waveform Dumping (Optional)
    // ========================================================================
    initial begin
        $fsdbDumpfile("tb_top.fsdb");
        $fsdbDumpvars(0, tb_top);
    end

endmodule : tb_top
